/*************************************************************************
                           GestionPriorite  -  description
                             -------------------
    début                : 24 févr. 2011
    copyright            : (C) 2011 par rcatolino
*************************************************************************/

//---------- Réalisation de la tâche <GestionPriorite> (fichier GestionPriorite.cpp) ---

/////////////////////////////////////////////////////////////////  INCLUDE
//-------------------------------------------------------- Include système
#include <set>
#include <vector>
#include <signal.h>
#include <iostream>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <time.h>
#include "/public/tp/tp-multitache/Outils.h"
#include "/public/tp/tp-multitache/Voiture.h"
//------------------------------------------------------ Include personnel
#include "GestionPriorite.h"

///////////////////////////////////////////////////////////////////  PRIVE
//------------------------------------------------------------- Constantes

//------------------------------------------------------------------ Types

//---------------------------------------------------- Variables statiques
static int balVoiture;
static int semEtatFeu;
static unsigned int *shmEtatFeu;
static set<pid_t> voitures; //tableau des pid de voitures
static TypeVoie voie;
static struct sigaction finGP; //declaration du handler
static struct sigaction finVoiture; //declaration du handler
static struct sembuf reserverEtatFeu = {1,-1,0};
static struct sembuf libererEtatFeu = {1,1,0};
//------------------------------------------------------ Fonctions privées
//static type nom ( liste de paramètres )
// Mode d'emploi :
//
// Contrat :
//
// Algorithme :
//
//{
//} //----- fin de nom
static void moteurGP()
{
	struct MsgVoiture newVoiture;
	unsigned int lastNum;
	vector<MsgVoiture> att;
	int voieLibre =0;
	int etatFeu = 0;
	enum TypeVoie voieOuverte1;
	enum TypeVoie voieOuverte2;
	struct msqid_ds opt;
	for (;;)
	{
		semop (semEtatFeu, &reserverEtatFeu,1);
		etatFeu = *shmEtatFeu;
		semop (semEtatFeu, &libererEtatFeu, 1);
		//cerr << "lecture de etatFeu pour GP" <<endl;
		if (etatFeu == 0x02)
		{
			//cerr << "le feu E-O est vert chez GP" << endl;
			voieOuverte1 = EST;
			voieOuverte2 = OUEST;
		}
		else if (etatFeu == 0x01)
		{
			//cerr << "le feu N-S est vert chez GP" << endl;
			voieOuverte1 = NORD;
			voieOuverte2 = SUD;
		}
		else 
		{
			//cerr << "les feux sont fermés chez GP :"<< etatFeu << endl;
			voieOuverte1 = AUCUNE;
			voieOuverte2 = AUCUNE;
		}

		int msgFlag = IPC_NOWAIT;
		if (att.size() == 0)
		{
			msgFlag = 0;
			cerr << "plus de voiture en attente sur la voie "<< voie << " time = "<<time(NULL)<<endl;
		}

		msgrcv (balVoiture,&newVoiture,TAILLE_MSG_VOITURE,(long)voie,msgFlag);
		cerr << "il y a " << att.size() << "voitures en attente sur la voie "<<voie<<" time = "<<time(NULL)<<endl;

		msgctl(balVoiture,IPC_STAT,&opt);
		cerr << "date de la derniere reception de voiture : "<<opt.msg_rtime<<endl;

		if (newVoiture.uneVoiture.numero != lastNum)
		{
			att.push_back(newVoiture);
			cerr << "ajout d'une voiture en attente voie :"<<voie<<endl;
			lastNum = newVoiture.uneVoiture.numero;
		}
		if (att.size() != 0)
		{
			enum TypeVoie entree = att.front().uneVoiture.entree;
			enum TypeVoie sortie = att.front().uneVoiture.sortie;
			int numVoiture = att.front().uneVoiture.numero;


			cerr << "voiture en attente : "<<numVoiture<<" de "<<entree<<" vers "<<sortie<<" time = "<<time(NULL)<<endl;

			if (entree == voieOuverte2 || entree == voieOuverte1)
			{
				voitures.insert(DeplacerVoiture(numVoiture,entree,sortie));
				if (voieLibre == numVoiture)
				{
					voieLibre = 0;
				}
				att.erase(att.begin());

				cerr << "passage de la voiture au feu vert" << " time = "<<time(NULL)<<endl;
				cerr <<numVoiture<<entree<<sortie<<endl;
				sleep(1);
			}
			else if (voieLibre == 0)
			{
				DessinerVoitureFeu(numVoiture,entree,sortie);
				voieLibre = numVoiture;
				cerr << "place libre sur la voie, attente de la voiture : "<<voieLibre<<" sur la voie "<< voie<<endl;
			}
			else 
			{
				sleep (1);
			}
		}
	}
}	
			
static void mortEnfant(int signum, siginfo_t * infos, void* context)
{
	set<int>::iterator it;
	pid_t numDeadChild = infos->si_pid;
	it = voitures.find(numDeadChild);
	voitures.erase(it);
	OperationVoie(MOINS,voie);

}
static void finDeTache(int signum)
{
	//on tue ses enfants :
	int cr;
	set<int>::iterator it = voitures.begin();
	while (it != voitures.end())
	{
		kill(*it,SIGUSR2);
		waitpid ( *it, &cr, 0 );
		if ( WIFEXITED ( cr ) )
			{
				cerr << "crdu = " << WEXITSTATUS ( cr ) << endl;
			}
		cerr << "mort d'une voiture" <<endl;
		it++;
	}
//On s'assure de rendre les ressources avant de mourir pour ne pas bloquer Menu ou GestionPriorites
	semctl ( semEtatFeu,1,SETVAL,1 );
	cerr << "fin de GP..." << endl;
	exit ( 0 );
}
static int creerHandlerFin()
{
	cerr << "création du handler de SIGUSR2 pour GestionPriorité" << endl;
	sigfillset(&finGP.sa_mask); 
	finGP.sa_handler = finDeTache; 
	finGP.sa_flags = 0; 
	return sigaction(SIGUSR2,&finGP,0); 
}
static int creerHandlerFinVoiture()
{
	cerr << "création du handler de SIGCHILD pour GestionPriorité" << endl;
	sigfillset(&finVoiture.sa_mask); 
	finVoiture.sa_sigaction = mortEnfant; 
	finVoiture.sa_flags = SA_SIGINFO; 
	return sigaction(SIGCHLD,&finVoiture,0); 
}

//////////////////////////////////////////////////////////////////  PUBLIC
//---------------------------------------------------- Fonctions publiques
//type Nom ( liste de paramètres )
// Algorithme :
//
//{
//} //----- fin de Nom
void IniGestionPriorite(int BALVOiture, int Sem, void* ShmEtat, TypeVoie voieEntree)
{
	balVoiture = BALVOiture; 	
	semEtatFeu = Sem;
	shmEtatFeu = (unsigned int *)ShmEtat;	

	if (creerHandlerFinVoiture() == -1)
	{
		cerr << "echec de la création du handler fin voiture" << endl;
	}
	if (creerHandlerFin() == -1)
	{
		cerr << "echec de la création du handler fin" << endl;
	}
	cerr << "fin de l'ini de gestion de priorité, debut du moteur" << endl;
	voie = voieEntree;
	moteurGP();

}
